﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;

namespace PeriodicalTaskDemo.Tasks
{
    public class XLogger : PeriodicalTask
    {
        /// <summary>
        /// 当前程序的日志列表缓存，保存所有实时的日志，通过 SaveLogs() 方法写入到文件。
        /// </summary>
        public static List<XLog> logs = new List<XLog>();

        /// <summary>
        /// 是否开启自动写入，默认为false。启动后每隔 AutoSaveInterval 秒调用一次 SaveLogs()。 
        /// </summary>
        public static bool AutoSave = true;

        /// <summary>
        /// 日志输出的目录，默认值为 ".\\logs"。
        /// </summary>
        public static string CurrentDirectory = "logs";

        /// <summary>
        /// 日志输出文件的文件名（不包括路径，路径由CurrentDirectory指定）默认值 applicaion.log，
        /// </summary>
        public static string LogFilename = "applicaion.log";


        public override void OnStart()
        {
            LogFilename = $"{DateTime.Now:yyyyMMdd}.csv";
            CurrentDirectory = Path.GetFullPath(CurrentDirectory);
            if (!Directory.Exists(CurrentDirectory))
                Directory.CreateDirectory(CurrentDirectory);
            Interval = 1000;
            Info("XLogger started.");
        }

        public override void DoWork()
        {
            // 如果不是自动保存就下一回合。
            if (AutoSave)
                SaveLogs();
        }

        public override void OnStop()
        {
            Info("XLogger stopped.");
            SaveLogs();
        }



        /// <summary>
        /// 将日志 logs 保存到文件 LogFile 中。logs数量为0则退出，以减少磁盘写入。
        /// </summary>
        public static void SaveLogs(string logfile = "")
        {
            // logs长度为0时则退出，减少磁盘写入。
            if (logs.Count == 0)
                return;

            StringBuilder sb = new StringBuilder();
            var copy_logs = new List<XLog>();
            lock (logs)
            {
                copy_logs.AddRange(logs);
                logs.Clear();
            }

            foreach (var log in copy_logs)
                sb.AppendLine(log.ToCsvString());
            Info("Logs copped.");

            try
            {
                if (string.IsNullOrEmpty(logfile))
                    logfile = Path.Combine(CurrentDirectory, LogFilename);

                if (!File.Exists(logfile))
                    File.AppendAllText(logfile, "Time,LogLevel,File,Line,ClassName,Method,Content\n", Encoding.UTF8);

                File.AppendAllText(logfile, sb.ToString(), Encoding.UTF8);
            }
            catch (Exception ex)
            {
                Error(ex.ToString());
            }
        }



        /// <summary>
        /// 记录日志，首先会添加到后台的 logs 中，然后再定时保存。
        /// </summary>
        /// <param name="content">日志内容。</param>
        /// <param name="logLevel">日志等级。</param>
        /// <param name="traceLevel">追踪等级，主要用于表示函数的嵌套层次，默认值为1，一般不需要调整。</param>
        /// <returns></returns>
        public static XLog Log(string content, XLogLevel logLevel = XLogLevel.INFO, int traceLevel = 1)
        {
            var log = new XLog(content, logLevel, traceLevel + 1);
            lock (logs)
            {
                logs.Add(log);
            }
            return log;
        }


        /// <summary>
        /// 写入FATAL类日志。
        /// </summary>
        /// <param name="content">日志内容。</param>
        /// <returns></returns>
        public static XLog Fatal(string content)
        {
            return Log(content, XLogLevel.FATAL, 2);
        }

        /// <summary>
        /// 写入ERROR类日志。
        /// </summary>
        /// <param name="content">日志内容。</param>
        /// <returns></returns>
        public static XLog Error(string content)
        {
            return Log(content, XLogLevel.ERROR, 2);
        }

        /// <summary>
        /// 写入WARN类日志。
        /// </summary>
        /// <param name="content">日志内容。</param>
        /// <returns></returns>
        public static XLog Warn(string content)
        {
            return Log(content, XLogLevel.WARNNING, 2);
        }

        /// <summary>
        /// 写入INFO类日志。
        /// </summary>
        /// <param name="content">日志内容。</param>
        /// <returns></returns>
        public static XLog Info(string content)
        {
            return Log(content, XLogLevel.INFO, 2);
        }

        /// <summary>
        /// 写入DEBUG类日志。
        /// </summary>
        /// <param name="content">日志内容。</param>
        /// <returns></returns>
        public static XLog Debug(string content)
        {
            return Log(content, XLogLevel.DEBUG, 2);
        }

        /// <summary>
        /// 只有满足条件时才会写日志。
        /// </summary>
        /// <param name="loginfo">日志信息。</param>
        /// <param name="condition">条件, true表示满足。</param>
        /// <param name="lv"></param>
        public static void LogIf(string loginfo, bool condition, XLogLevel lv = XLogLevel.INFO)
        {
            if (condition)
                Log(loginfo, lv);
        }


    }
}

